package com.xiaoh.dormitoryrepairreportbackend.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xiaoh.dormitoryrepairreportbackend.common.ErrorCode;
import com.xiaoh.dormitoryrepairreportbackend.constant.WorkOrderConstant;
import com.xiaoh.dormitoryrepairreportbackend.exception.BusinessException;
import com.xiaoh.dormitoryrepairreportbackend.mapper.WorkOrderMapper;
import com.xiaoh.dormitoryrepairreportbackend.model.dto.ai.AiAssignmentResult;
import com.xiaoh.dormitoryrepairreportbackend.model.dto.common.PageResponse;
import com.xiaoh.dormitoryrepairreportbackend.model.dto.workorder.WorkOrderQueryRequest;
import com.xiaoh.dormitoryrepairreportbackend.model.dto.workorder.WorkOrderResponse;
import com.xiaoh.dormitoryrepairreportbackend.model.dto.workorder.WorkOrderStatsResponse;
import com.xiaoh.dormitoryrepairreportbackend.model.entity.GeneralUser;
import com.xiaoh.dormitoryrepairreportbackend.model.entity.RepairCategory;
import com.xiaoh.dormitoryrepairreportbackend.model.entity.WorkOrder;
import com.xiaoh.dormitoryrepairreportbackend.model.entity.WorkOrderLog;
import com.xiaoh.dormitoryrepairreportbackend.service.*;
import com.xiaoh.dormitoryrepairreportbackend.utils.QueryUtils;
import com.xiaoh.dormitoryrepairreportbackend.utils.WorkOrderConverter;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 工单表 服务实现类
 */
@Service
@Slf4j
public class WorkOrderServiceImpl extends ServiceImpl<WorkOrderMapper, WorkOrder>
        implements WorkOrderService {

    @Resource
    private WorkOrderLogService workOrderLogService;

    @Resource
    private GeneralUserService generalUserService;

    @Resource
    private RepairCategoryService repairCategoryService;

    @Resource
    private AiWorkOrderAssignmentService aiWorkOrderAssignmentService;

    @Resource
    private NotificationService notificationService;

    @Override
    public String generateWorkOrderId() {
        // 生成格式：WO + 年月日 + 6位随机数
        String dateStr = DateUtil.format(DateUtil.date(), "yyyyMMdd");
        String randomStr = IdUtil.fastSimpleUUID().substring(0, 6).toUpperCase();
        return "WO" + dateStr + randomStr;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createWorkOrder(WorkOrder workOrder) {
        // 生成工单编号
        workOrder.setWorkOrderId(generateWorkOrderId());
        workOrder.setStatus(WorkOrderConstant.Status.PENDING);

        boolean result = this.save(workOrder);
        if (!result) {
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "创建工单失败");
        }

        // 记录日志
        createWorkOrderLog(workOrder.getId(), workOrder.getReporterId(), "CREATE", "创建工单");

        return workOrder.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createWorkOrderWithAiAssignment(WorkOrder workOrder) {
        // 1. 创建工单
        Long workOrderId = createWorkOrder(workOrder);
        // 2. 在事务提交后异步执行 AI 分配，避免读取未提交数据/锁等待
        if (TransactionSynchronizationManager.isActualTransactionActive()) {
            TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
                @Override
                public void afterCommit() {
                    assign(workOrder);
                }
            });
        }
        return workOrderId;
    }

    private void assign(WorkOrder workOrder) {
        Long workOrderId = workOrder.getId();
        // 2. 尝试AI自动分配
        try {
            AiAssignmentResult aiResult = aiWorkOrderAssignmentService.assignWorkOrder(workOrder);

            if (aiResult.isSuccess() && aiResult.getRecommendedMaintenanceId() != null) {
                // AI分配成功，自动分配工单  暂时不管事务失效的问题
                boolean assignSuccess = assignWorkOrder(workOrderId, aiResult.getRecommendedMaintenanceId());

                if (assignSuccess) {
                    // 发送通知给学生和维修工
                    sendAssignmentNotifications(workOrder, aiResult.getRecommendedMaintenanceId(),
                            "AI自动分配: " + aiResult.getReason());

                    log.info("工单 {} AI自动分配成功，分配给维修工 {}, 原因: {}",
                            workOrderId, aiResult.getRecommendedMaintenanceId(), aiResult.getReason());
                } else {
                    log.warn("工单 {} AI推荐成功但分配失败，需要管理员手动分配", workOrderId);
                    sendAdminNotification(workOrder, "AI推荐成功但自动分配失败，请手动分配");
                }
            } else {
                // AI分配失败，通知管理员手动分配
                log.warn("工单 {} AI分配失败: {}", workOrderId, aiResult.getErrorMessage());
                sendAdminNotification(workOrder, "AI无法自动分配工单，原因: " + aiResult.getErrorMessage());
            }
        } catch (Exception e) {
            log.error("工单 {} AI分配过程异常", workOrderId, e);
            sendAdminNotification(workOrder, "AI分配服务异常，请手动分配工单");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean assignWorkOrder(Long workOrderId, Long handlerId) {
        WorkOrder workOrder = this.getById(workOrderId);
        if (workOrder == null) {
            throw new BusinessException(ErrorCode.WORK_ORDER_NOT_EXIST);
        }

        var status = workOrder.getStatus();
        if (status == null || !status.equals(WorkOrderConstant.Status.PENDING)) {
            throw new BusinessException(ErrorCode.WORK_ORDER_STATUS_ERROR, "工单状态不允许分配");
        }

        workOrder.setHandlerId(handlerId);
        workOrder.setStatus(WorkOrderConstant.Status.IN_PROGRESS);

        boolean result = this.updateById(workOrder);
        if (result) {
            createWorkOrderLog(workOrderId, handlerId, "ASSIGN", "分配工单");
        }

        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateWorkOrderStatus(Long workOrderId, Integer status, Long operatorId) {
        WorkOrder workOrder = this.getById(workOrderId);
        if (workOrder == null) {
            throw new BusinessException(ErrorCode.WORK_ORDER_NOT_EXIST);
        }

        // 验证状态转换是否合法
        validateStatusTransition(workOrder.getStatus(), status);

        workOrder.setStatus(status);
        workOrder.setUpdatedAt(LocalDateTime.now());

        boolean result = this.updateById(workOrder);
        if (result) {
            // 记录日志
            WorkOrderLog log = new WorkOrderLog();
            log.setWorkOrderId(workOrderId);
            log.setOperatorId(operatorId);
            log.setOperationType("STATUS_UPDATE");
            log.setContent("更新工单状态为：" + getStatusName(status));
            log.setCreatedAt(LocalDateTime.now());
            workOrderLogService.save(log);
        }

        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean reviewWorkOrder(Long workOrderId, Integer rating, String reviewComment, Long operatorId) {
        WorkOrder workOrder = this.getById(workOrderId);
        if (workOrder == null) {
            throw new BusinessException(ErrorCode.WORK_ORDER_NOT_EXIST);
        }

        var status = workOrder.getStatus();
        if (status == null || !status.equals(WorkOrderConstant.Status.COMPLETED)) {
            throw new BusinessException(ErrorCode.WORK_ORDER_STATUS_ERROR, "工单状态不允许评价");
        }

        workOrder.setRating(rating);
        workOrder.setReviewComment(reviewComment);
        workOrder.setStatus(WorkOrderConstant.Status.REVIEWED);

        boolean result = this.updateById(workOrder);
        if (result) {
            createWorkOrderLog(workOrderId, operatorId, "REVIEW", "评价工单，评分：" + rating + "星");
        }

        return result;
    }

    /**
     * 发送分配通知给学生和维修工
     */
    private void sendAssignmentNotifications(WorkOrder workOrder, Long maintenanceId, String reason) {
        try {
            // 通知学生
            notificationService.createNotification(
                    workOrder.getReporterId(),
                    "工单已分配",
                    String.format("您的工单 %s 已分配给维修工处理。%s", workOrder.getTitle(), reason),
                    "WORK_ORDER",
                    workOrder.getId()
            );

            // 通知维修工
            notificationService.createNotification(
                    maintenanceId,
                    "新工单分配",
                    String.format("您有新的工单需要处理：%s，地址：%s", workOrder.getTitle(), workOrder.getLocation()),
                    "WORK_ORDER",
                    workOrder.getId()
            );
        } catch (Exception e) {
            log.error("发送分配通知失败", e);
        }
    }

    /**
     * 发送通知给管理员
     */
    private void sendAdminNotification(WorkOrder workOrder, String message) {
        try {
            // 这里简化处理，实际应该查询所有管理员
            // 假设管理员ID为1（可以从配置或数据库查询）
            notificationService.createNotification(
                    1L, // 管理员ID
                    "工单需要手动分配",
                    String.format("工单 %s 需要手动分配。%s", workOrder.getTitle(), message),
                    "WORK_ORDER",
                    workOrder.getId()
            );
        } catch (Exception e) {
            log.error("发送管理员通知失败", e);
        }
    }

    /**
     * 创建工单日志的通用方法
     */
    private void createWorkOrderLog(Long workOrderId, Long operatorId, String operationType, String content) {
        WorkOrderLog log = new WorkOrderLog();
        log.setWorkOrderId(workOrderId);
        log.setOperatorId(operatorId);
        log.setOperationType(operationType);
        log.setContent(content);
        log.setCreatedAt(LocalDateTime.now());
        workOrderLogService.save(log);
    }

    @Override
    public PageResponse<WorkOrderResponse> listWorkOrderPageWithConditions(WorkOrderQueryRequest queryRequest) {
        QueryWrapper<WorkOrder> queryWrapper = new QueryWrapper<>();

        // 1. 根据报修人账号查询报修人ID
        if (StrUtil.isNotBlank(queryRequest.getReporterAccount())) {
            QueryWrapper<GeneralUser> reporterQuery = new QueryWrapper<>();
            reporterQuery.like("account_name", queryRequest.getReporterAccount());
            List<GeneralUser> reporters = generalUserService.list(reporterQuery);
            if (reporters.isEmpty()) {
                return PageResponse.empty(queryRequest.getCurrent(), queryRequest.getPageSize().longValue());
            }
            List<Long> reporterIds = reporters.stream().map(GeneralUser::getId).collect(Collectors.toList());
            queryWrapper.in("reporter_id", reporterIds);
        }

        // 2. 根据处理人账号查询处理人ID
        if (StrUtil.isNotBlank(queryRequest.getHandlerAccount())) {
            QueryWrapper<GeneralUser> handlerQuery = new QueryWrapper<>();
            handlerQuery.like("account_name", queryRequest.getHandlerAccount());
            List<GeneralUser> handlers = generalUserService.list(handlerQuery);
            if (handlers.isEmpty()) {
                return PageResponse.empty(queryRequest.getCurrent(), queryRequest.getPageSize().longValue());
            }
            List<Long> handlerIds = handlers.stream().map(GeneralUser::getId).collect(Collectors.toList());
            queryWrapper.in("handler_id", handlerIds);
        }

        // 3. 根据报修类别名称查询类别ID
        if (StrUtil.isNotBlank(queryRequest.getCategoryName())) {
            QueryWrapper<RepairCategory> categoryQuery = new QueryWrapper<>();
            categoryQuery.like("category_name", queryRequest.getCategoryName());
            List<RepairCategory> categories = repairCategoryService.list(categoryQuery);
            if (categories.isEmpty()) {
                return PageResponse.empty(queryRequest.getCurrent(), queryRequest.getPageSize().longValue());
            }
            List<Integer> categoryIds = categories.stream().map(RepairCategory::getId).collect(Collectors.toList());
            queryWrapper.in("category_id", categoryIds);
        }

        // 4. 添加其他查询条件
        QueryUtils.addLikeCondition(queryWrapper, "title", queryRequest.getTitle());
        QueryUtils.addLikeCondition(queryWrapper, "location", queryRequest.getLocation());
        QueryUtils.addEqCondition(queryWrapper, "status", queryRequest.getStatus());
        QueryUtils.addTimeRangeCondition(queryWrapper, "created_at",
                queryRequest.getCreatedAtStart(), queryRequest.getCreatedAtEnd());

        // 5. 查询总记录数（包含分页条件）
        Long total = this.count(queryWrapper);

        // 6. 添加游标分页
        QueryUtils.addCursorPagination(queryWrapper, queryRequest.getLastId(), queryRequest.getPageSize());

        // 7. 查询工单列表
        List<WorkOrder> workOrders = this.list(queryWrapper);
        if (workOrders.isEmpty()) {
            return PageResponse.empty(queryRequest.getCurrent(), queryRequest.getPageSize().longValue());
        }

        // 8. 批量查询用户信息
        List<Long> userIds = WorkOrderConverter.extractUserIds(workOrders);
        Map<Long, GeneralUser> userMap = Map.of();
        if (!userIds.isEmpty()) {
            List<GeneralUser> users = generalUserService.listByIds(userIds);
            userMap = users.stream().collect(Collectors.toMap(GeneralUser::getId, Function.identity()));
        }

        // 9. 批量查询类别信息
        List<Integer> categoryIds = WorkOrderConverter.extractCategoryIds(workOrders);
        Map<Integer, RepairCategory> categoryMap = Map.of();
        if (!categoryIds.isEmpty()) {
            List<RepairCategory> categories = repairCategoryService.listByIds(categoryIds);
            categoryMap = categories.stream().collect(Collectors.toMap(RepairCategory::getId, Function.identity()));
        }

        // 10. 转换为响应DTO
        List<WorkOrderResponse> workOrderResponses = WorkOrderConverter.toWorkOrderResponseList(workOrders, userMap, categoryMap);

        // 11. 获取下一页游标
        Long nextCursor = QueryUtils.getNextCursor(workOrders);

        // 12. 计算当前页码
        Long current = QueryUtils.calculateCurrentPage(queryRequest.getLastId(), queryRequest.getPageSize(), total);

        // 13. 构建分页响应
        return PageResponse.of(workOrderResponses, current, queryRequest.getPageSize().longValue(), total, nextCursor);
    }

    @Override
    public WorkOrderStatsResponse getWorkOrderStats() {
        WorkOrderStatsResponse stats = new WorkOrderStatsResponse();

        // 查询总工单数（排除逻辑删除的）
        QueryWrapper<WorkOrder> totalWrapper = new QueryWrapper<>();
        Long totalCount = this.count(totalWrapper);
        stats.setTotalCount(totalCount);

        // 查询待处理工单数
        QueryWrapper<WorkOrder> pendingWrapper = new QueryWrapper<>();
        pendingWrapper.eq("status", WorkOrderConstant.Status.PENDING);
        Long pendingCount = this.count(pendingWrapper);
        stats.setPendingCount(pendingCount);

        // 查询处理中工单数
        QueryWrapper<WorkOrder> inProgressWrapper = new QueryWrapper<>();
        inProgressWrapper.eq("status", WorkOrderConstant.Status.IN_PROGRESS);
        Long inProgressCount = this.count(inProgressWrapper);
        stats.setInProgressCount(inProgressCount);

        // 查询已完成工单数
        QueryWrapper<WorkOrder> completedWrapper = new QueryWrapper<>();
        completedWrapper.eq("status", WorkOrderConstant.Status.COMPLETED);
        Long completedCount = this.count(completedWrapper);
        stats.setCompletedCount(completedCount);

        // 查询已评价工单数
        QueryWrapper<WorkOrder> reviewedWrapper = new QueryWrapper<>();
        reviewedWrapper.eq("status", WorkOrderConstant.Status.REVIEWED);
        Long reviewedCount = this.count(reviewedWrapper);
        stats.setReviewedCount(reviewedCount);

        // 查询已取消工单数
        QueryWrapper<WorkOrder> cancelledWrapper = new QueryWrapper<>();
        cancelledWrapper.eq("status", WorkOrderConstant.Status.CANCELLED);
        Long cancelledCount = this.count(cancelledWrapper);
        stats.setCancelledCount(cancelledCount);

        return stats;
    }

    /**
     * 验证工单状态转换是否合法
     *
     * @param currentStatus 当前状态
     * @param newStatus     新状态
     */
    private void validateStatusTransition(Integer currentStatus, Integer newStatus) {
        if (currentStatus == null || newStatus == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "工单状态不能为空");
        }

        // 如果状态没有变化，直接返回
        if (currentStatus.equals(newStatus)) {
            return;
        }

        // 定义合法的状态转换规则
        switch (currentStatus) {
            case WorkOrderConstant.Status.PENDING: // 待处理
                // 待处理可以转为：处理中、已取消
                if (newStatus != WorkOrderConstant.Status.IN_PROGRESS &&
                        newStatus != WorkOrderConstant.Status.CANCELLED) {
                    throw new BusinessException(ErrorCode.WORK_ORDER_STATUS_ERROR,
                            "待处理状态只能转为处理中或已取消");
                }
                break;

            case WorkOrderConstant.Status.IN_PROGRESS: // 处理中
                // 处理中可以转为：已完成、已取消
                if (newStatus != WorkOrderConstant.Status.COMPLETED &&
                        newStatus != WorkOrderConstant.Status.CANCELLED) {
                    throw new BusinessException(ErrorCode.WORK_ORDER_STATUS_ERROR,
                            "处理中状态只能转为已完成或已取消");
                }
                break;

            case WorkOrderConstant.Status.COMPLETED: // 已完成
                // 已完成只能转为：已评价（通过评价接口）
                if (newStatus != WorkOrderConstant.Status.REVIEWED) {
                    throw new BusinessException(ErrorCode.WORK_ORDER_STATUS_ERROR,
                            "已完成状态只能通过评价转为已评价");
                }
                break;

            case WorkOrderConstant.Status.REVIEWED: // 已评价
                // 已评价是终态，不能再转换
                throw new BusinessException(ErrorCode.WORK_ORDER_STATUS_ERROR,
                        "已评价状态不能再变更");

            case WorkOrderConstant.Status.CANCELLED: // 已取消
                // 已取消是终态，不能再转换
                throw new BusinessException(ErrorCode.WORK_ORDER_STATUS_ERROR,
                        "已取消状态不能再变更");

            default:
                throw new BusinessException(ErrorCode.WORK_ORDER_STATUS_ERROR,
                        "未知的工单状态");
        }
    }

    /**
     * 获取状态名称
     *
     * @param status 状态码
     * @return 状态名称
     */
    private String getStatusName(Integer status) {
        if (status == null) {
            return "未知";
        }

        return switch (status) {
            case WorkOrderConstant.Status.PENDING -> "待处理";
            case WorkOrderConstant.Status.IN_PROGRESS -> "处理中";
            case WorkOrderConstant.Status.COMPLETED -> "已完成";
            case WorkOrderConstant.Status.REVIEWED -> "已评价";
            case WorkOrderConstant.Status.CANCELLED -> "已取消";
            default -> "未知状态(" + status + ")";
        };
    }
}
